package com.qingfeng.medical.biz.hosp.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qingfeng.currency.dozer.DozerUtils;
import com.qingfeng.medical.base.handler.GeneralAuthException;
import com.qingfeng.medical.base.result.ResultCodeEnum;
import com.qingfeng.medical.biz.hosp.dao.HospDepartmentMapper;
import com.qingfeng.medical.biz.hosp.domain.dto.HospDepartmentSaveDTO;
import com.qingfeng.medical.biz.hosp.domain.dto.HospDepartmentUpdateDTO;
import com.qingfeng.medical.biz.hosp.domain.dto.HospDepartmentUpdateStatusDTO;
import com.qingfeng.medical.biz.hosp.domain.entity.HospDepartment;
import com.qingfeng.medical.biz.hosp.domain.ro.HospDepartmentApiRo;
import com.qingfeng.medical.biz.hosp.domain.ro.HospDepartmentRo;
import com.qingfeng.medical.biz.hosp.domain.vo.DepPatientVo;
import com.qingfeng.medical.biz.hosp.domain.vo.HospDepartmentApiVo;
import com.qingfeng.medical.biz.hosp.domain.vo.HospDepartmentExcelVo;
import com.qingfeng.medical.biz.hosp.domain.vo.HospDepartmentVo;
import com.qingfeng.medical.biz.hosp.listener.HospDepartmentListener;
import com.qingfeng.medical.biz.hosp.service.HospDepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 科室管理
 *
 * @author 清风学Java
 * @date 2023-04-08 23:43:31
 */
@Service
public class HospDepartmentServiceImpl extends ServiceImpl<HospDepartmentMapper, HospDepartment> implements HospDepartmentService {

    @Autowired
    private DozerUtils dozerUtils;

    /**
     * 科室门诊信息Excel导入
     *
     * @param file
     */
    @Override
    @Transactional(rollbackFor = GeneralAuthException.class)
    public void importDepartment(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(),
                            HospDepartmentExcelVo.class,
                            new HospDepartmentListener(this)
                    )
                    .sheet()
                    .doRead();
        } catch (IOException e) {
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "科室/门诊信息导入异常");
        }
    }

    /**
     * 导出科室模板
     *
     * @param response
     */
    @Override
    public void exportTemplate(HttpServletResponse response) {
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //设置URLEncoder.encode可以解决中文乱码问题   这个和EasyExcel没有关系
            response.setHeader("Content-Disposition",
                    "attachment;filename=" +
                            URLEncoder.encode("科室-门诊信息模板", "UTF-8") +
                            ".xlsx");

            // 调用方法实现写操作
            EasyExcel.write(response.getOutputStream(), HospDepartmentExcelVo.class)
                    .sheet("科室门诊信息")
                    .doWrite(Collections.emptyList());
        } catch (Exception e) {
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "科室/门诊信息模板导出异常，请重试！");
        }
    }

    @Override
    public void exportDict(HttpServletResponse response) {
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            //设置URLEncoder.encode可以解决中文乱码问题   这个和EasyExcel没有关系
            response.setHeader("Content-Disposition",
                    "attachment;filename=" +
                            URLEncoder.encode("科室-门诊信息", "UTF-8") +
                            ".xlsx");

            List<HospDepartmentExcelVo> hospDepartmentExcelVos = baseMapper.selectList(null)
                    .stream()
                    .map(h -> HospDepartmentExcelVo.builder()
                            .depName(h.getDepName())
                            .depCode(h.getDepCode())
                            .patientName(h.getPatientName())
                            .patientCode(h.getPatientCode())
                            .intro(h.getIntro())
                            .status(h.getStatus() == 1 ? "启用" : "不启用")
                            .build())
                    .collect(Collectors.toList());

            // 调用方法实现写操作
            EasyExcel.write(response.getOutputStream(), HospDepartmentExcelVo.class)
                    .sheet("科室门诊信息")
                    .doWrite(hospDepartmentExcelVos);
        } catch (Exception e) {
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "科室门诊信息导出异常，请重试！");
        }
    }

    /**
     * 科室门诊列表
     *
     * @param depName
     * @param patientName
     * @return
     */
    @Override
    public List<HospDepartmentVo> hospDepartmentList(String depName, String patientName) {
        LambdaQueryWrapper<HospDepartment> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(depName)) {
            wrapper.eq(HospDepartment::getDepName, depName);
        }
        if (StrUtil.isNotBlank(patientName)) {
            wrapper.eq(HospDepartment::getPatientName, patientName);
        }
        // 查询出所有的科室门诊信息
        List<HospDepartment> hospDepartments = baseMapper.selectList(wrapper);
        if (CollUtil.isEmpty(hospDepartments)) {
            return Collections.emptyList();
        }
        // 按科室进行分组
        Map<String, List<HospDepartment>> hospDepartmentsMap = hospDepartments.stream()
                .collect(Collectors.groupingBy(
                                HospDepartment::getDepName
                        )
                );

        // 封装数据
        return hospDepartments.stream()
                .map(HospDepartment::getDepName)
                .distinct()
                .map(name -> {
                    HospDepartmentVo build = HospDepartmentVo.builder()
                            .depName(name)
                            .depCode(hospDepartmentsMap.get(name).get(0).getDepCode())
                            .hospDepartmentRo(
                                    hospDepartmentsMap.get(name)
                                            .stream()
                                            .map(h -> HospDepartmentRo.builder()
                                                    .id(h.getId())
                                                    .patientName(h.getPatientName())
                                                    .patientCode(h.getPatientCode())
                                                    .intro(h.getIntro())
                                                    .status(h.getStatus())
                                                    .build()
                                            )
                                            .collect(Collectors.toList())
                            )
                            .build();
                    Integer statusCount = hospDepartmentsMap.get(name)
                            .stream()
                            .filter(h -> h.getStatus() == 0)
                            .collect(Collectors.counting())
                            .intValue();
                    build.setStatus(statusCount == hospDepartmentsMap.get(name).size() ? 0 : 1);
                    return build;
                })
                .collect(Collectors.toList());
    }

    /**
     * 保存科室信息
     *
     * @param hospDepartmentSaveDTO
     */
    @Override
    public void saveHospDepartment(HospDepartmentSaveDTO hospDepartmentSaveDTO) {
        // 校验科室名和门诊名是否唯一
        List<HospDepartment> hospDepartments = baseMapper.selectList(
                new LambdaQueryWrapper<HospDepartment>()
                        .eq(HospDepartment::getDepName, hospDepartmentSaveDTO.getDepName())
                        .eq(HospDepartment::getPatientName, hospDepartmentSaveDTO.getPatientName())
        );

        if (CollUtil.isNotEmpty(hospDepartments)) {
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "科室-门诊名重复，请修改");
        }

        // 校验科室编码是否唯一
        hospDepartments = baseMapper.selectList(
                new LambdaQueryWrapper<HospDepartment>()
                        .eq(HospDepartment::getDepCode, hospDepartmentSaveDTO.getDepCode())
                        .ne(HospDepartment::getDepName, hospDepartmentSaveDTO.getDepName())
        );

        if (CollUtil.isNotEmpty(hospDepartments)) {
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "科室编码重复，请修改");
        }

        // 校验门诊编码是否唯一
        hospDepartments = baseMapper.selectList(
                new LambdaQueryWrapper<HospDepartment>()
                        .eq(HospDepartment::getPatientCode, hospDepartmentSaveDTO.getPatientCode())
        );

        if (CollUtil.isNotEmpty(hospDepartments)) {
            throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "门诊编码重复，请修改");
        }

        // 进行保存
        baseMapper.insert(dozerUtils.map2(hospDepartmentSaveDTO, HospDepartment.class));
    }

    /**
     * 修改科室门诊信息
     *
     * @param hospDepartmentUpdateDTO
     */
    @Override
    public void updateHospDepartment(HospDepartmentUpdateDTO hospDepartmentUpdateDTO) {
        // 判断是修改科室还是修改门诊信息  修改科室——》没有门诊信息
        if (StrUtil.isNotBlank(hospDepartmentUpdateDTO.getOldPatientName())) {
            // 修改门诊信息 检查门诊名是否重复
            if (!hospDepartmentUpdateDTO.getOldPatientName().equals(hospDepartmentUpdateDTO.getPatientName())) {
                List<HospDepartment> hospDepartments = baseMapper.selectList(new LambdaQueryWrapper<HospDepartment>()
                        .eq(HospDepartment::getDepName, hospDepartmentUpdateDTO.getOldDepName())
                        .eq(HospDepartment::getPatientName, hospDepartmentUpdateDTO.getPatientName())
                );
                if (CollUtil.isNotEmpty(hospDepartments)) {
                    throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "门诊名重复，请修改");
                }
            }

            if (!hospDepartmentUpdateDTO.getOldPatientCode().equals(hospDepartmentUpdateDTO.getPatientCode())) {
                List<HospDepartment> hospDepartments = baseMapper.selectList(new LambdaQueryWrapper<HospDepartment>()
                        .eq(HospDepartment::getPatientCode, hospDepartmentUpdateDTO.getPatientCode())
                );
                if (CollUtil.isNotEmpty(hospDepartments)) {
                    throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "门诊编码重复，请修改");
                }
            }

            this.updateBatchById(
                    baseMapper.selectList(
                                    new LambdaQueryWrapper<HospDepartment>()
                                            .eq(HospDepartment::getDepName, hospDepartmentUpdateDTO.getOldDepName())
                                            .eq(HospDepartment::getPatientName, hospDepartmentUpdateDTO.getOldPatientName())
                            ).stream()
                            .map(h -> {
                                h.setPatientName(hospDepartmentUpdateDTO.getPatientName());
                                h.setPatientCode(hospDepartmentUpdateDTO.getPatientCode());
                                h.setIntro(hospDepartmentUpdateDTO.getIntro());
                                return h;
                            })
                            .collect(Collectors.toList())
            );

        } else {
            // 修改科室信息  检查科室信息是否重复
            if (!hospDepartmentUpdateDTO.getDepName().equals(hospDepartmentUpdateDTO.getOldDepName())) {
                List<HospDepartment> hospDepartments = baseMapper.selectList(
                        new LambdaQueryWrapper<HospDepartment>()
                                .eq(HospDepartment::getDepName, hospDepartmentUpdateDTO.getDepName())

                );

                if (CollUtil.isNotEmpty(hospDepartments)) {
                    throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "科室名重复，请修改");
                }

            }

            // 校验科室编码
            if (!hospDepartmentUpdateDTO.getDepCode().equals(hospDepartmentUpdateDTO.getOldDepCode())) {
                List<HospDepartment> hospDepartments = baseMapper.selectList(
                        new LambdaQueryWrapper<HospDepartment>()
                                .eq(HospDepartment::getDepCode, hospDepartmentUpdateDTO.getDepCode())
                );

                if (CollUtil.isNotEmpty(hospDepartments)) {
                    throw new GeneralAuthException(ResultCodeEnum.FAIL.getCode(), "科室编码重复，请修改");
                }

            }

            // 查出包含所有科室信息的数据
            this.updateBatchById(
                    baseMapper.selectList(
                                    new LambdaQueryWrapper<HospDepartment>()
                                            .eq(HospDepartment::getDepName, hospDepartmentUpdateDTO.getOldDepName())
                            )
                            .stream()
                            .map(h -> {
                                h.setDepName(hospDepartmentUpdateDTO.getDepName());
                                h.setDepCode(hospDepartmentUpdateDTO.getDepCode());
                                return h;
                            })
                            .collect(Collectors.toList()));

        }
    }

    /**
     * 获取科室门诊信息
     *
     * @return
     */
    @Override
    public List<DepPatientVo> findDepPatient() {
        List<HospDepartment> hospDepartmentList = baseMapper.selectList(null);
        // 根据科室进行分组
        Map<String, List<HospDepartment>> hospDepartmentMap = hospDepartmentList.stream()
                .collect(Collectors.groupingBy(HospDepartment::getDepName));

        return hospDepartmentMap.entrySet()
                .stream()
                .map(entry ->
                        DepPatientVo.builder()
                                .label(entry.getKey())
                                .value(0L)
                                .children(
                                        entry.getValue()
                                                .stream()
                                                .map(h -> DepPatientVo.builder()
                                                        .label(h.getPatientName())
                                                        .value(h.getId())
                                                        .children(null)
                                                        .build())
                                                .collect(Collectors.toList())
                                )
                                .build()
                )
                .collect(Collectors.toList());
    }

    /**
     * 修改状态
     *
     * @param hospDepartmentUpdateStatusDTO
     */
    @Override
    public void updateStatus(HospDepartmentUpdateStatusDTO hospDepartmentUpdateStatusDTO) {
        if (ObjectUtil.isNotNull(hospDepartmentUpdateStatusDTO.getId())) {
            // 修改门诊状态
            baseMapper.updateById(
                    baseMapper.selectById(hospDepartmentUpdateStatusDTO.getId())
                            .setStatus(hospDepartmentUpdateStatusDTO.getStatus())
            );
        } else {
            // 修改科室下的所有门诊信息
            this.updateBatchById(
                    baseMapper.selectList(new LambdaQueryWrapper<HospDepartment>()
                                    .eq(HospDepartment::getDepName, hospDepartmentUpdateStatusDTO.getDepName()))
                            .stream()
                            .map(h -> h.setStatus(hospDepartmentUpdateStatusDTO.getStatus()))
                            .collect(Collectors.toList()));
        }
    }

    /**
     * 前台科室门诊列表
     *
     * @return
     */
    @Override
    public List<HospDepartmentApiVo> hospDepartmentApiList() {
        List<HospDepartmentVo> hospDepartmentVos = this.hospDepartmentList(null, null);

        if (CollUtil.isEmpty(hospDepartmentVos)) {
            return Collections.emptyList();
        }

        AtomicLong atomicLong = new AtomicLong(1);
        return hospDepartmentVos.stream()
                .filter(h -> h.getStatus() != 0)
                .map(h -> {
                            HospDepartmentApiVo build = HospDepartmentApiVo.builder()
                                    .id(atomicLong.get())
                                    .depName(h.getDepName())
                                    .depCode(h.getDepCode())
                                    .hospDepartmentApiRo(
                                            h.getHospDepartmentRo()
                                                    .stream()
                                                    .filter(d -> d.getStatus() != 0)
                                                    .map(d -> HospDepartmentApiRo.builder()
                                                            .id(d.getId())
                                                            .patientName(d.getPatientName())
                                                            .patientCode(d.getPatientCode())
                                                            .build()
                                                    )
                                                    .collect(Collectors.toList())
                                    )
                                    .build();

                            atomicLong.addAndGet(1);
                            return build;
                        }
                )
                .collect(Collectors.toList());
    }
}